4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 namespace Microsoft
.JScript
{
19 using System
.Collections
;
20 using System
.Globalization
;
21 using System
.Reflection
;
23 public sealed class JSLocalField
: JSVariableField
{
24 internal int slotNumber
;
25 internal IReflect inferred_type
; //Records a guess of what the type of the field is. null = unknown.
26 private ArrayList dependents
; //A list of other fields whose types have been inferred (guessed) based on the inferred type of this field.
27 //The dependend fields need to have their guesses changed.
28 internal bool debugOn
; // whether this local field was in a section of code with debug set or not. Control emitting debug info for the local
29 internal JSLocalField outerField
; //If this field is a copy of an outer scope field, the outer scope field is kept in here.
30 internal bool isDefined
; //Indicates whether an assignment to the field has been encountered.
31 internal bool isUsedBeforeDefinition
;
33 public JSLocalField(String name
, RuntimeTypeHandle handle
, int slotNumber
)
34 : this(name
, null, slotNumber
, Missing
.Value
){
35 this.type
= new TypeExpression(new ConstantWrapper(Type
.GetTypeFromHandle(handle
), null));
36 this.isDefined
= true;
39 internal JSLocalField(String name
, FunctionScope scope
, int slotNumber
, Object
value)
40 : base(name
, scope
, FieldAttributes
.Static
|FieldAttributes
.Public
) {
41 this.slotNumber
= slotNumber
;
42 this.inferred_type
= null;
43 this.dependents
= null;
46 this.outerField
= null;
47 this.isDefined
= false;
48 this.isUsedBeforeDefinition
= false;
51 public override Type FieldType
{
53 if (this.type
!= null)
54 return base.FieldType
;
56 return Convert
.ToType(this.GetInferredType(null));
60 internal override IReflect
GetInferredType(JSField inference_target
){
61 if (this.outerField
!= null)
62 return this.outerField
.GetInferredType(inference_target
);
63 if (this.type
!= null)
64 return base.GetInferredType(inference_target
);
65 if (this.inferred_type
== null || this.inferred_type
== Typeob
.Object
)
67 if (inference_target
!= null && inference_target
!= this){
68 if (this.dependents
== null)
69 this.dependents
= new ArrayList();
70 this.dependents
.Add(inference_target
);
72 return this.inferred_type
;
75 public override Object
GetValue(Object obj
){
76 if ((this.attributeFlags
&FieldAttributes
.Literal
) != (FieldAttributes
)0 && !(this.value is FunctionObject
))
79 while (obj
is BlockScope
) obj
= ((BlockScope
)obj
).GetParent();
80 StackFrame sf
= (StackFrame
)obj
;
81 JSLocalField f
= this.outerField
;
82 int slot
= this.slotNumber
;
85 sf
= (StackFrame
)sf
.GetParent();
88 return sf
.localVars
[slot
];
92 internal void SetInferredType(IReflect ir
, AST expr
){
93 this.isDefined
= true;
94 if (this.type
!= null)
95 return; //The local variable has a type annotation.
96 if (this.outerField
!= null){
97 this.outerField
.SetInferredType(ir
, expr
);
100 if (Convert
.IsPrimitiveNumericTypeFitForDouble(ir
))
102 else if (ir
== Typeob
.Void
)
104 if (this.inferred_type
== null)
105 this.inferred_type
= ir
;
107 //Check to see if ir is compatible with this.inferred_type. If not, generalize this.inferred_type to Object and invalidate dependants.
108 if (ir
== this.inferred_type
) return;
109 if (!Convert
.IsPrimitiveNumericType(this.inferred_type
) || !Convert
.IsPrimitiveNumericType(ir
) ||
110 !Convert
.IsPromotableTo(ir
, this.inferred_type
)){
111 this.inferred_type
= Typeob
.Object
;
112 if (this.dependents
!= null)
113 for (int i
= 0, n
= this.dependents
.Count
; i
< n
; i
++)
114 ((JSLocalField
)this.dependents
[i
]).SetInferredType(Typeob
.Object
, null);
119 public override void SetValue(Object obj
, Object
value, BindingFlags invokeAttr
, Binder binder
, CultureInfo locale
){
120 if (this.type
!= null)
121 value = Convert
.Coerce(value, this.type
);
122 while (obj
is BlockScope
) obj
= ((BlockScope
)obj
).GetParent();
123 StackFrame sf
= (StackFrame
)obj
;
124 JSLocalField f
= this.outerField
;
125 int slot
= this.slotNumber
;
128 sf
= (StackFrame
)sf
.GetParent();
131 if (sf
.localVars
== null) return; //happens when assigning to a constant from latebound code
132 sf
.localVars
[slot
] = value;